package com.scc.websocket;
import com.alibaba.fastjson.JSON;
import com.scc.pojo.Message;
import com.scc.service.MessageService;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;

@ServerEndpoint("/chat/{applyId}")
@Component
@Slf4j
// 实现ApplicationContextAware接口，用于获取Spring的应用上下文，以便手动获取Bean
public class WebSocketChat implements ApplicationContextAware {

    // 用于存放各个员工对应的WebSocket会话对象，以员工ID作为键，方便后续根据员工ID查找对应的会话来发送消息
    private static final Map<Integer, Session> sessionMap = new HashMap<>();

    @Autowired
    private MessageService messageService;

    // 用于保存Spring的应用上下文，通过实现ApplicationContextAware接口的方法来进行赋值
    private static ApplicationContext applicationContext;

    // 实现ApplicationContextAware接口的方法，Spring会自动调用此方法，将应用上下文传递进来
    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        WebSocketChat.applicationContext = applicationContext;
    }

    // 获取MessageService实例的方法，通过从保存的应用上下文中获取对应的Bean
    private MessageService getMessageService() {
        return applicationContext.getBean(MessageService.class);
    }

    // 当有WebSocket客户端连接时会触发此方法，由WebSocket容器调用
    @OnOpen
    public void onOpen(Session session, @PathParam("applyId") Integer empId) {
        log.info("ws已经连接");
        // 将新连接的客户端对应的会话对象添加到sessionMap中，方便后续根据员工ID找到对应的会话
        sessionMap.put(empId, session);
    }

    // 当WebSocket客户端发送消息时会触发此方法，由WebSocket容器调用
    @OnMessage
    public void onMessage(String message) {
        // 使用FastJSON将接收到的JSON格式的消息字符串解析为Message对象，方便后续操作
        Message msg = JSON.parseObject(message, Message.class);
        // 获取消息要发送到的目标员工的ID
        int toEmpId = msg.getToEmpId();
        try {
            // 根据目标员工的ID从sessionMap中获取对应的会话对象，如果不存在则返回null
            Session session = sessionMap.get(toEmpId);
            if (session!= null) {
                // 使用FastJSON将构建好的Message对象转换为JSON格式的字符串，以便发送给客户端
                String msgJson = JSON.toJSONString(msg);
                // 通过异步方式发送消息到对应的客户端，如果客户端离线等情况会抛出异常
                session.getAsyncRemote().sendText(msgJson);
                log.info("发送成功{}", msgJson);
            }
        } catch (Exception e) {
            // 如果发送消息出现异常，比如目标客户端离线等情况，将消息保存到数据库中（通过MessageService操作）
            getMessageService().insertMessage(msg);
        }
        // 无论消息是否发送成功，都将当前员工发送的消息保存到数据库中（通过MessageService操作）
        getMessageService().insertMessage(msg);
    }

    // 当WebSocket客户端关闭连接时会触发此方法，由WebSocket容器调用
    @OnClose
    public void onClose(@PathParam("applyId") Integer empId) {
        log.info("socket已关闭");
        // 从sessionMap中移除对应的会话对象，因为该员工已经下线了
        sessionMap.remove(empId);
    }

    // 当WebSocket连接出现错误时会触发此方法，由WebSocket容器调用
    @OnError
    public void onError(Session session, Throwable error) {
        log.info(error.getMessage());
    }
}